package spider.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spider.netty.server.handler.WebSocketServerInitializer;
import spider.zookeeper.node.NodeManager;
import spider.zookeeper.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.Timer;
import java.util.TimerTask;

/**
 * WebSocketServer
 *
 * @author Archx[archx@foxmail.com]
 * @date 2017/4/8.
 */
public class WebSocketServer {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    private WebSocketServerInitializer initializer;
    private NodeManager nodeManager;

    private int boosCount;
    private int workerCount;
    private boolean keepAlive = true;
    private int backlog = 128;
    private int port;
    private boolean webContainer;
    private boolean cluster;

    @PostConstruct
    public void bootstrap() {
        if (webContainer) {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    launch();
                }
            }, 1000);
        } else {
            launch();
        }
    }

    /**
     * 启动
     */
    private void launch() {

        EventLoopGroup bossGroup = bossGroup();
        EventLoopGroup workerGroup = workerGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
        bootstrap.childHandler(initializer);
        bootstrap.option(ChannelOption.SO_BACKLOG, backlog).childOption(ChannelOption.SO_KEEPALIVE, keepAlive);
        //bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, 64, 64));

        try {
            ChannelFuture f = bootstrap.bind(port).sync();
            logger.info("> Netty server start");

            bindZookeeper();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            logger.error(StringUtils.printStackTrace(e));
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    /**
     * 绑定ZK节点管理
     */
    private void bindZookeeper() {
        if (cluster) {
            Thread nodeThread = new Thread(new Runnable() {
                public void run() {
                    nodeManager.establish();
                }
            });
            nodeThread.setDaemon(true);
            nodeThread.start();
        }
    }

    private EventLoopGroup bossGroup() {
        if (boosCount > 0)
            return new NioEventLoopGroup(boosCount);
        return new NioEventLoopGroup();
    }

    private EventLoopGroup workerGroup() {
        if (workerCount > 0)
            return new NioEventLoopGroup(workerCount);
        return new NioEventLoopGroup();
    }

    public void setInitializer(WebSocketServerInitializer initializer) {
        this.initializer = initializer;
    }

    public void setNodeManager(NodeManager nodeManager) {
        this.nodeManager = nodeManager;
    }

    public void setBoosCount(int boosCount) {
        this.boosCount = boosCount;
    }

    public void setWorkerCount(int workerCount) {
        this.workerCount = workerCount;
    }

    public void setKeepAlive(boolean keepAlive) {
        this.keepAlive = keepAlive;
    }

    public void setBacklog(int backlog) {
        this.backlog = backlog;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setWebContainer(boolean webContainer) {
        this.webContainer = webContainer;
    }

    public void setCluster(boolean cluster) {
        this.cluster = cluster;
    }
}
